
#include "MainHeader.h"

GBAMethods::GBAMethods()
{

}

GBAMethods::~GBAMethods()
{

}

u32             GBAMethods::RawWrite(u8 * srcp, u32 size, u8 * dstp)
{
   u32             i;

   for (i = 0; i < size - 1; i++)
   {
      *dstp = *srcp;
      dstp++;
      srcp++;
   }
   *dstp = *srcp;

   return size;
}

//===========================================================================
// Difference filter
// ===========================================================================

//===========================================================================
// Run length encoding (bytes)
// ===========================================================================
u32             GBAMethods::RLCompWrite(u8 * srcp, u32 size, u8 * dstp)
{
   u32             RLDstCount;  // Compression data size in bytes

   u32             RLSrcCount;  // Size of data that is the targeted for

                                // compression, after processing is complete
                                // (bytes)

   u8              RLCompFlag;  // for run length encoding use 1

   u8              runLength;   // Run length

   u8              rawDataLength; // Length of data that is not run

   u32             i;

   u8             *startp;      // Points to the beginning of data that is

                                // the compression target for one process
                                // loop.

   // data header    (size is after extraction)
   // *(u32 *)dstp   = size << 8 | RL_CODE_HEADER;  // data header
   RLDstCount = 0;

   RLSrcCount = 0;
   rawDataLength = 0;
   RLCompFlag = 0;

   while (RLSrcCount < size)
   {
      startp = &srcp[RLSrcCount]; // Setting the compression target data

      for (i = 0; i < 128; i++) // Data sized 0-127 can be expressed as 7-bit

      {
         // Reached the end of the compression target data.
         if (RLSrcCount + rawDataLength >= size)
         {
            rawDataLength = (u8) (size - RLSrcCount);
            break;
         }
         if (RLSrcCount + rawDataLength + 2 < size)
         {
            if (startp[i] == startp[i + 1] &&
                startp[i] == startp[i + 2])
            {
               RLCompFlag = 1;
               break;
            }
         }
         rawDataLength++;
      }

      // St|e data that will not be encoded.
      // If the 8th bit of the data length st|age byte is 0, it not an
      // encoding data sequence.
      // Data length is the number -1. Therefore 0-127 becomes 1-128.
      if (rawDataLength)
      {
         dstp[RLDstCount++] = rawDataLength - 1; // "Data length -1" st|age
                                                 // (7 bits)

         for (i = 0; i < rawDataLength; i++)
         {
            dstp[RLDstCount++] = srcp[RLSrcCount++];
         }
         rawDataLength = 0;
      }
      // Run length encoding
      if (RLCompFlag)
      {
         runLength = 3;
         for (i = 3; i < 128 + 2; i++)
         {
            // Reached the end of the data for compression
            if (RLSrcCount + runLength >= size)
            {
               runLength = (u8) (size - RLSrcCount);
               break;
            }
            // If there is a pause in the run
            if (srcp[RLSrcCount] != srcp[RLSrcCount + runLength])
            {
               break;
            }
            // Continuing the run
            runLength++;
         }

         // If the 8th bit of the data length st|age byte is 1, it is an
         // encoded data sequence.
         dstp[RLDstCount++] = 0x80 | (runLength - 3); // Add 3 from the
                                                      // bottom and st|e
                                                      // 3-130

         dstp[RLDstCount++] = srcp[RLSrcCount];
         RLSrcCount += runLength;
         RLCompFlag = 0;
      }
   }

   // 4-byte b|der alignment
   // 0 data for alignment is not included in the data size
   i = 0;
   while ((RLDstCount + i) & 0x3)
   {
      dstp[RLDstCount + i] = 0;
      i++;
   }

   return RLDstCount;
}

//===========================================================================
// LZ77 compression
// ===========================================================================
u32             GBAMethods::LZCompWrite(u8 * srcp, u32 size, u8 * dstp, u8 lzSearchOffset)
{
   u32             LZDstCount;  // Compression data size in bytes

   u32             LZSrcCount;  // Size of data that is the target of

                                // compression, after processing is complete
                                // (bytes)

   u8              LZCompFlags; // Flag sequence that indicates whether

                                // compression | not.

   u8             *LZCompFlagsp; // Points to the mem|y region that st|es

                                 // LZCompFlags

   u8             *compressingDataHeadp; // Beginning address of the current

                                         // data region that is targeted for
                                         // compression.

   u8             *searchp;     // Beginning address of the matching data

                                // search region

   u16             tmpOffset;   // Offset to the matching data (mid-search

                                // data)

   u8              tmpLength;   // Matching data length (mid-search data)

   u16             lastOffset;  // Offset to matching data (longest matching

                                // data at that time) 

   u8              lastLength;  // Matching data length (longest matching

                                // data at that time)

   u8              i;

   // dbg_printf_lz( stderr, "LZCompWrite\tsize=%d\tlzSearchOffset=%d\n",
   // size, lzSearchOffset );

   *(u32 *) dstp = size << 8 | LZ_CODE_HEADER; // data header

   LZDstCount = 4;

   LZSrcCount = 0;
   while (LZSrcCount < size)
   {
      LZCompFlags = 0;
      LZCompFlagsp = &dstp[LZDstCount++]; // st|age target of flag series

      // flag series is st|ed as 8-bit data, so 8-time loop
      for (i = 0; i < 8; i++)
      {
         LZCompFlags <<= 1; // the first time (i=0) carries no special
                            // significance

         lastOffset = 0;
         lastLength = 0;
         compressingDataHeadp = &srcp[LZSrcCount];

         // VRAM is two-byte access so (since there are cases where data is
         // read from VRAM)
         // search target data must be data from before two byte.
         // 
         // offset is st|ed as 12-bit so less than 4096
         for (tmpOffset = lzSearchOffset; tmpOffset <= LZSrcCount && tmpOffset <= 4096; tmpOffset++)
         {
            if (LZSrcCount >= size)
            {
               break;
            }
            searchp = &srcp[LZSrcCount - tmpOffset]; // search data region
                                                     // setting

            if (*searchp == *compressingDataHeadp) // matching data found

            {
               // data length is st|ed with four bits, so less than 18 (put
               // on the 3 clog)
               for (tmpLength = 1; tmpLength <= 16 + 2; tmpLength++)
               {
                  if (searchp[tmpLength] != compressingDataHeadp[tmpLength])
                  {
                     break;
                  }
               }
               if (tmpLength > 16 + 2)
               {
                  tmpLength = 18; // so it doesn't become 19

               }
               if (LZSrcCount + tmpLength >= size)
               {
                  tmpLength = (u8) (size - LZSrcCount);
               }
               // update the longest matching data
               if (tmpLength >= 3 && tmpLength > lastLength)
               {
                  lastOffset = tmpOffset;
                  lastLength = tmpLength;
                  LZCompFlags |= 0x01;
               }
            }
         }
         // st|age of LZCompFlags one compressed data
         if (LZSrcCount < size)
         {
            if ((LZCompFlags & 0x01) == 0)
            { // no compression

               dstp[LZDstCount++] = srcp[LZSrcCount++];
            } else
            {
               // offset is separated into top four bits and bottom eight
               // bits and st|ed
               dstp[LZDstCount++] = (lastLength - 3) << 4 | (lastOffset - 1) >> 8;
               dstp[LZDstCount++] = (lastOffset - 1) & 0xff;
               LZSrcCount += lastLength;
            }
         }
      } // 8-time loop ends

      *LZCompFlagsp = LZCompFlags; // st|e flag series

   }

   // four byte boundary alignment
   // don't include data 0 for alignment in data size
   i = 0;
   while ((LZDstCount + i) & 0x3)
   {
      dstp[LZDstCount + i] = 0;
      i++;
   }

   return LZDstCount;
}

//===========================================================================
// Huffman Encoding
// ===========================================================================

//##############################################################################################
// ##############################################################################################

//==================================================================================
// Expand Raw data
// ==================================================================================
s32             GBAMethods::RawRead(u8 * srcp, u32 size, u8 * dstp)
{
   // memcpy(dstp, srcp, size);
   u32             i;

   for (i = 0; i < size - 1; i++)
   {
      *dstp = *srcp;
      dstp++;
      srcp++;
   }
   *dstp = *srcp;

   return size;
}

//==================================================================================
// Expand difference compression data
// ==================================================================================

//==================================================================================
// Expanding run length compressed data
// ==================================================================================
s32             GBAMethods::RLCompRead(u8 * srcp, u32 size, u8 * dstp)
{
   u32             RLDstCount;  // Expansion data size in bytes

   u32             RLSrcCount;  // Size of data that is targeted for

                                // expansion in bytes--after processing
                                // (bytes).

   u8              length;      // Data length

   u32             i;

   RLSrcCount = 0;
   RLDstCount = 0;
   while (RLDstCount < size)
   {
      if (srcp[RLSrcCount] & 0x80) // decoding process (run length encoded)

      {
         length = srcp[RLSrcCount++] & 0x7f; // st|e data length (three geta
                                             // are w|n, so consider it
                                             // actually +3)

         dstp[RLDstCount++] = srcp[RLSrcCount];
         dstp[RLDstCount++] = srcp[RLSrcCount];
         dstp[RLDstCount++] = srcp[RLSrcCount];
         for (i = 3; i < (u8) (length + 3); i++)
         {
            // dstp[ RLDstCount++ ] = LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
            srcp[RLSrcCount];
         }
         RLSrcCount++;
      } else // Copy raw data (not run length encoded)

      {
         length = srcp[RLSrcCount++]; // (same as srcp[RLSrcCount] & 0x7f)

         for (i = 0; i < (u8) (length + 1); i++)
         { // +1 because data length is st|ed -1.

            dstp[RLDstCount] = srcp[RLSrcCount];
            RLDstCount++;
            RLSrcCount++;
         }
      }
   }

   // 4-byte b|der alignment
   // 0 data for alignment is not included in the data size.
   i = 0;
   while ((RLDstCount + i) & 0x3)
   {
      dstp[RLDstCount + i] = 0;
      i++;
   }

   return RLDstCount;
}

//==================================================================================
// LZ77Compressed data extraction
// ==================================================================================
s32             GBAMethods::LZ77UnComp(u8 * source, u8 * dest)
{
   long            size = 0;

   u32             header = (source[0] | (source[1] << 8) | (source[2] << 16) | (source[3] << 24));

   // printf(Buffer,"%d",header>> 8);

   // sMessage(Buffer);
   int             i, j, in = 4, out = 0;
   int             length, offset;
   u32             windowOffset;

   int             len = header >> 8;

   while (len > 0)
   {
      u8              d = source[in++];

      for (i = 0; i < 8; i++)
      {
         if (d & 0x80)
         {
            u16             data = ((source[in] << 8) | source[in + 1]);

            in += 2;
            length = (data >> 12) + 3;
            offset = (data & 0x0FFF);
            windowOffset = out - offset - 1;
            for (j = 0; j < length; j++)
            {
               dest[out++] = dest[windowOffset++];
               len--;
               if (len == 0)
                  return header >> 8;
            }
         } else
         {
            dest[out++] = source[in++];
            len--;
            if (len == 0)
               return header >> 8;
         }
         d <<= 1;
      }
   }
   return header >> 8;
/*
 * lz77 GL;
 * 
 * 
 * GL.source = 0;
 * memcpy(&GL.cFile, &source,32691);
 * int i=0;
 * 
 * for(i=0;i<32691;i++) GL.cFile[i]=source[i];
 * GL.BIOS_LZ77UnCompWram();
 * 
 * 
 * for(i=0;i<GL.length;i++)dest[i]=GL.cFile[i];
 * return GL.length;
 */
}

//==================================================================================
// Palette
// ==================================================================================
void           *GBAMethods::DecodePal(short *palGBA, long *palPC, int numpals, char palpos)
{

   int             R, g, b, i, ii, s = 0;
   long            index = 0;

   for (ii = 0; ii < numpals; ii++)
   {
      index = 0x10 * ii;

      for (i = 0; i < 16; i++)
      {

         R = ((palGBA[index + i] & 0x1F) << 3);
         g = ((palGBA[index + i] >> 5) & 0x1F) << 3;
         b = (((palGBA[index + i] >> 10) & 0x1f) << 3);
         palPC[index + i] = RGB(R, g, b);
      }
   }
   return 0;
}
void           *GBAMethods::EncodePal(short *palGBA, long *palPC, int numpals, char palpos)
{

   int             i, ii, s = 0;

   // u16 clr;
   u32             clr = 0;;
   long            index = 0;

   for (ii = 0; ii < numpals; ii++)
   {
      index = 0x10 * ii;

      for (i = 0; i < 16; i++)
      {
         clr = palPC[index + i] >> 3;
         palGBA[index + i] = (u16) ((clr & 0x1F) | (clr & 0x1F00) >> 3 | (clr & 0x1F0000) >> 6);

         // clr = (palPC[index + i]>>3);
         palGBA[index + i] = (u16) (((palPC[index + i] >> 3) & 0x1F) | ((palPC[index + i] >> 3) & 0x1F00) >> 3 | ((palPC[index + i] >> 3) & 0x1F0000) >> 6);
      }
   }
   return 0;
}
/*
 * long GBAMethods::ZMUncompRle(u8* cmp, u8* uncmp, long size, int LoopSeq ){
 * char nm=0;
 * char buf[100];
 * long src , tgt, sze, i,j;
 * 
 * u8 rlebyte, data,Mode;
 * 
 * src = 0;
 * 
 * tgt = 0;
 * 
 * 
 * for( j = 0; j <  2;j++){
 * // sprintf(buf,"compressed offset is: %x",src);
 * // sMessage(buf);
 * Mode = cmp[src++];
 * 
 * if (Mode == 1){
 * rlebyte = cmp[src++];
 * 
 * while (rlebyte > 0){
 * if(tgt == size) return  src - 1;
 * sze = rlebyte & 0x7F;
 * if (rlebyte & 0x80){
 * data = cmp[src++];
 * 
 * for(i = -1;i<sze;i++){
 * //if(tgt == size*2) return  src - 1;
 * uncmp[tgt] = data;
 * tgt = tgt + (LoopSeq == 1? 2:1);
 * }
 * }else{
 * for(i = 0;i<sze;i++){
 * //if(tgt == size*2) return  src - 1;
 * data = cmp[src++];
 * uncmp[tgt] = data;
 * tgt = tgt + (LoopSeq == 1? 2:1);
 * }
 * }
 * rlebyte = cmp[src++];
 * 
 * }
 * }
 * 
 * 
 * if (LoopSeq == 1) 
 * if (j == 0)  tgt =1;
 * 
 * }
 * 
 * 
 * 
 * return src - 1;
 * }
 */
long            GBAMethods::ZMUncompRle(u16 arg0, u8 * arg1, u8 * arg2)
{

   u8             *src = (u8 *) arg1, *dst = (u8 *) arg2;

   u32             jj, ii, nn;
   u32             ctrl, type;

   type = 0;
   nn = 0x3000;

   switch (arg0)
   {
   case 0:
      type = 0x0800;
      break;
   case 3:
      type = 0x2000;
      break;
   default:
      type = 0x1000;
   }

   nn = 0x2000;

   // DMAFill(3, 0, arg2, nn, 16);

   for (ii = 0; ii < 2; ii++)
   {
      dst = (u8 *) & arg2[ii];
      if (*src++ == 1) // 8 control field

      {
         while (1)
         {
            ctrl = *src++;
            if (ctrl == 0)
               break;

            else if (ctrl & 0x80)
            {
               nn = ctrl & 0x7F;
               if (*src)
                  for (jj = 0; jj < nn; jj++)
                     dst[2 * jj] = *src;
               src++;
            } else
            {
               nn = ctrl;
               for (jj = 0; jj < nn; jj++)
                  dst[2 * jj] = src[jj];
               src += nn;
            }

            dst += 2 * nn;
         }
      } else // RLE16

      {
         while (1)
         {
            ctrl = src[0] << 8 | src[1];
            src += 2;
            if (ctrl == 0)
               break;

            if (ctrl & 0x8000)
            {
               nn = ctrl & 0x7FFF;
               if (*src)
                  for (jj = 0; jj < nn; jj++)
                     dst[2 * jj] = *src;
               src++;
            } else
            {
               nn = ctrl;
               for (jj = 0; jj < nn; jj++)
                  dst[2 * jj] = src[jj];
               src += nn;
            }
            dst += 2 * nn;
         }
      }
   }

   return type;
}

int             GBAMethods::RLEComp(u8 * cmp, u8 * uncmp)
{
   u32             src = 0;
   u32             tgt = 0;

   for (int j = 0; j < 2; j++)
   {

      u8              mode = cmp[src++];

      if (mode == 1)
      {
         // printf("8Bit RLE\n");
         u8              rlebyte = cmp[src++];

         while (rlebyte != 0)
         {
            u8              sze = rlebyte & 0x7F;

            if (rlebyte & 0x80)
            {
               u8              data = cmp[src++];

               for (int i = 0; i < sze; i++)
               {
                  uncmp[tgt] = data;
                  tgt += 2;
               }
            } else
            {
               for (int i = 0; i < sze; i++)
               {
                  u8              data = cmp[src++];

                  uncmp[tgt] = data;
                  tgt += 2;
               }
            }
            rlebyte = cmp[src++];
         }
      } else
      {
         // printf("16Bit RLE\n");

         u16             rlebyte = cmp[src++];

         rlebyte = rlebyte << 8;
         rlebyte = rlebyte | cmp[src++];

         while (rlebyte != 0)
         {
            u16             sze = rlebyte & 0x7FFF;

            if (rlebyte & 0x8000)
            {
               u8              data = cmp[src++];

               for (int i = 0; i < sze; i++)
               {
                  uncmp[tgt] = data;
                  tgt += 2;
               }
            } else
            {
               for (int i = 0; i < sze; i++)
               {
                  u8              data = cmp[src++];

                  uncmp[tgt] = data;
                  tgt += 2;
               }
            }

            rlebyte = cmp[src++];
            rlebyte = rlebyte << 8;
            rlebyte = rlebyte | cmp[src++];
         }

      }
      if (j == 0)
         tgt = 1;
   }
   return tgt - 1;

}
int             GBAMethods::ZMCompress(FILE * fp)
{
   long            offset = 0;

   long            tlength;
/*
   // Save only if it's RLE compression otherwise FUCK IT
   if (fp)
   {
      if (RoomHeader.bBg0 == 16 && ThisForeground.SDirty == 1)
      {

         memset(GBA.CompBuffer, 0, 64691);
         tlength = compress(GBA.CompBuffer, (u8 *) ThisForeground.TileBuf2D, (ThisForeground.X * ThisForeground.Y) * 2);
         offset = GBA.FindFreeSpace(tlength + 4, 0xFF);
         if (offset != 0)
         {

            RoomHeader.lForeground = 0x8000000 + offset;

            fseek(fp, offset, SEEK_SET);
            fputc(ThisForeground.X, fp);
            fputc(ThisForeground.Y, fp);
            fwrite(GBA.CompBuffer, sizeof(char), tlength, fp);
            GBA.Reopen();
         } else
         {
            sMessage("Could not save the Foreground.");
         }
      }
      if (RoomHeader.bBg1 == 16 && ThisLevelData.SDirty == 1)
      {

         memset(GBA.CompBuffer, 0, 64691);
         tlength = compress(GBA.CompBuffer, (u8 *) ThisLevelData.TileBuf2D, (long) ((ThisLevelData.X * ThisLevelData.Y) * 2));
         offset = GBA.FindFreeSpace(tlength + 4, 0xFF);
         if (offset != 0)
         {

            RoomHeader.lLevelData = 0x8000000 + offset;
            fseek(fp, offset, SEEK_SET);
            fputc(ThisLevelData.X, fp);
            fputc(ThisLevelData.Y, fp);
            fwrite(GBA.CompBuffer, sizeof(char), tlength, fp);
            GBA.Reopen();
         } else
         {
            sMessage("Could not save Level Data.");
         }
      }
      if (RoomHeader.bBg2 == 16 && ThisBackLayer.SDirty == 1)
      {

         memset(GBA.CompBuffer, 0, 64691);

         tlength = compress(GBA.CompBuffer, (u8 *) ThisBackLayer.TileBuf2D, (ThisBackLayer.X * ThisBackLayer.Y) * 2);
         offset = GBA.FindFreeSpace(tlength + 4, 0xFF);
         if (offset != 0)
         {

            RoomHeader.lBackLayer = 0x8000000 + offset;
            fseek(fp, offset, SEEK_SET);
            fputc(ThisBackLayer.X, fp);
            fputc(ThisBackLayer.Y, fp);
            fwrite(GBA.CompBuffer, sizeof(char), tlength, fp);
            GBA.Reopen();
         } else
         {
            sMessage("Could not save the BackLayer.");
         }
      }
      if (ThisClipData.SDirty == 1)
      {
         memset(GBA.CompBuffer, 0, 64691);
         tlength = compress(GBA.CompBuffer, (u8 *) ThisClipData.TileBuf2D, (ThisClipData.X * ThisClipData.Y) * 2);
         offset = GBA.FindFreeSpace(tlength + 4, 0xFF);
         if (offset != 0)
         {
            RoomHeader.lClipData = 0x8000000 + offset;
            fseek(fp, offset, SEEK_SET);
            fputc(ThisClipData.X, fp);
            fputc(ThisClipData.Y, fp);
            fwrite(GBA.CompBuffer, sizeof(char), tlength, fp);
            GBA.Reopen();
         } else
         {
            sMessage("Could not save Clip Data.");
         }
      }
   }*/
   return 0;
}

long            GBAMethods::compress(u8 cmp[], u8 uncmp[], unsigned long sze)
{
   // int sze = 3;

   u32             cmpptr = 0;
   u32             sizeptr = 0;
   u32             dataptr = 0;
   u32             rl = 0;

   u32             samebytecount = 0;

   for (int j = 0; j < 2; j++)
   {
      cmp[cmpptr++] = 1;
      while (sze > dataptr)
      {
         rl = 2;
         while (uncmp[dataptr] == uncmp[dataptr + 2] && uncmp[dataptr + 2] == uncmp[dataptr + 4] && rl < 0x7F && sze > dataptr)
         {

            dataptr += 2;
            rl++;
         }

         if (rl > 2)
         {
            // printf("run found s=%02X\n", rl);
            cmp[cmpptr++] = (u8) ((rl | 0x80) & 0xFF);
            cmp[cmpptr++] = uncmp[dataptr];
            dataptr += 4;
         }
         sizeptr = cmpptr;
         cmpptr++;

         rl = 0;
         while ((uncmp[dataptr] != uncmp[dataptr + 2] || uncmp[dataptr + 2] != uncmp[dataptr + 4]) && rl < 0x7F && sze > dataptr)
         {

            cmp[cmpptr++] = uncmp[dataptr];
            dataptr += 2;
            rl++;
         }
         // printf("norun found s=%02X\n", rl);
         if (rl != 0)
            cmp[sizeptr] = (u8) rl;
         else
            cmpptr--;
      }
      cmp[cmpptr++] = 0;

      dataptr = 1;
   }

   return cmpptr;

}
/*
 * 
 * long GBAMethods::FindFreeSpace(long bNo, u8 bConst){//bNo is how many bytes, bConst is what
 * //value to look for 
 * 
 * // returns offset of "free space" block
 * //  or -1 if no such block found
 * 
 * FILE* file = fopen(GBA.FileLoc,"rb");
 * if(!file)
 * return -1;
 * 
 * 
 * //bNo+=0x100;//Look for an extra free 256 bytes.
 * int ch;
 * long runstart = -1;
 * long runcount = 0;
 * int flength=EOF;
 * while(1)
 * {
 * ch = fgetc(file);  // get character (byte)
 * if(ch == EOF)  // if end of file
 * {
 * runstart = -1; // eof reached before we found block
 * return  runstart ;
 * 
 * }
 * 
 * if((u8)ch == bConst)
 * {
 * if(!runcount) // start of run
 * runstart = (long)ftell(file) - 1;
 * 
 * ++runcount;
 * if(runcount >= bNo)  // block found
 * break;
 * } else {
 * 
 * runcount = 0;
 * }
 * 
 * }
 * 
 * fclose(file);
 * 
 * return runstart;
 * }
 */
u32             GBAMethods::LZ77Comp(u32 decmpsize, u8 * source, u8 * dest)
{
//lz77 GL;
   // GL.BIOS_LZ77CompWram(source,decmpsize,1);
   // memcpy(dest,GL.filedata,GL.filedatapos);
   /*
    * long cmpsize=0; RECORD src= { source, decmpsize, 1 }; RECORD dst= {
    * NULL, 0, 0 }; cmpsize=cprs_gba_lz77(&dst, &src); memcpy(dest,dst.data,
    * cmpsize); free(dst.data); return cmpsize;
    */
   int             unp = 0;
   int             cop = 4;

   int             dist;
   int             maxchain;
   int             ende;
   int             chain;
   int             idpos;
   unsigned short  bits = 0;

   while (unp < decmpsize)
   {
      bits = bits >> 1;
      if (bits == 0)
      {
         dest[cop] = 0;
         idpos = cop++;
         bits = 0x80;
      }
      dist = 0;
      maxchain = 0;

      ende = min(0xFFF, unp);

      for (int i = 1; i < ende; i++)
      {
         chain = 0;
         while (source[unp + chain] == source[unp - i + chain] && chain < 0x12 && unp + chain < decmpsize
                && unp - i + chain != unp - 1)
         {
            chain++;
         }
         if (chain > maxchain)
         {
            dist = i;
            maxchain = chain;
         }
         if (chain == 0x12)
            break;
      }

      if (maxchain > 2)
      {
         dest[idpos] |= bits;
         dest[cop] = (((maxchain - 3) & 0xF) << 4) | (((dist - 1) >> 8) & 0xF);
         dest[cop + 1] = dist - 1 & 0xFF;
         cop += 2;
         unp += maxchain;
      } else
      {
         dest[cop++] = source[unp++];
      }
   }

   while (cop % 4)
   {
      dest[cop++] = 0;
   }

   u32             Header = 0x10 | (decmpsize << 8);

   memcpy(dest, &Header, 4);
   return cop;

   // return GL.filedatapos;
}

void            GBAMethods::Reopen()
{

   fclose(ROM);
   ROM = fopen(FileLoc, "r+b");

}
long            GBAMethods::FindFreeSpace(long bNo, u8 bConst)
{ // bNo is how many bytes, bConst is what
   // value to look for 

   // returns offset of "free space" block
   // or -1 if no such block found

   FILE           *file = fopen(GBA.FileLoc, "rb");

   if (!file)
      return -1;

   bNo += 0x100; // Look for an extra free 256 bytes. -- still not sure what
                 // this does,
   // but whatever

   int             ch;
   long            runstart = -1;
   long            runcount = 0;

   fseek(file, 0, SEEK_SET);//DefAddress, SEEK_SET);
 checkagain:
   while (1)
   {
      ch = fgetc(file); // get character (byte)

      if (ch == EOF) // if end of file

      {
         runstart = -1; // eof reached before we found block

         break;

      }
      if ((u8) ch == bConst)
      {
         if (!runcount) // start of run

            runstart = (long) ftell(file) - 1;

         ++runcount;
         if (runcount >= bNo) // block found

            break;
      } else
      {
         runstart = -1;
         runcount = 0;
      }

   }
   if (runstart == -1)
   {
      fseek(file, 0, SEEK_SET);

      goto checkagain;
   }
   if (runstart != -1)
      while (runstart % 4)
         runstart++;
   return runstart;
}
int             GBAMethods::ReturnFileName(char *Filter, char *FilePath, int sofn)
{
   return ReturnFileName(Filter, FilePath, sofn, 1);

}
int             GBAMethods::ReturnFileName(char *Filter, char *FilePath, int sofn, u8 Existance)
{
   int             Flag = 0;

   if (Existance == 1)
      Flag = OFN_FILEMUSTEXIST;

   OPENFILENAME    ofn;

   memset(&ofn, 0, sizeof(ofn));
   ofn.lStructSize = sizeof(ofn);
   ofn.hwndOwner = NULL;
   ofn.lpstrFile = FilePath;
   ofn.nMaxFile = sofn;
   ofn.hInstance = NULL;
   ofn.lpstrFilter = Filter;
   ofn.nFilterIndex = 1;
   ofn.Flags = OFN_EXPLORER | Flag;
   return GetOpenFileName(&ofn);
}

int             GBAMethods::ReturnEOF(FILE * fp)
{
   // Takes a file, and finds the end of it
   int             sz = 0;

   // fseek(fp,0,SEEK_END);
   char            blah;

   fseek(fp, 0, SEEK_SET);
   while (1)
   {
      blah = fgetc(fp);
      if (feof(fp) != 0)
         break;
      sz++;
   }

   return sz;
}
int GBAMethods::Read(int Amount, void* pointer){


 return fread(pointer, 1, Amount, ROM);
}

int GBAMethods::Write(int Amount, void* pointer){


 return fwrite(pointer, 1, Amount, ROM);
}

int GBAMethods::Seek(long Offset){

return fseek(ROM, Offset, SEEK_SET); 

}